package com.vcommon.core.managers
{
import com.vcommon.core.errors.SingletonError;
import com.vcommon.core.managers.utils.TweenUtil;
import com.vcommon.core.utils.ArrayUtil;
import com.vcommon.core.utils.DepthUtil;

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import flash.utils.Dictionary;

/**
 * The PopUpManager singleton class creates new top-level windows and
 * places or removes those windows from the layer on top of all other
 * visible windows.
 * @author Sean
 */
public class PopUpManager
{
	/**
	 *  @private
	 */
	private static var instance:PopUpManager;
	
	/**
	 *  Returns the sole instance of this singleton class,
	 *  creating it if it does not already exist.
	 */
	public static function getInstance():PopUpManager
	{
		if (!instance)
		{
			instance = new PopUpManager();
		}
		return instance;
	}
	
	public function PopUpManager()
	{
		if (instance)
		{
			throw new SingletonError(instance);
		}
	}
	//==========================================================================
	//  Variables
	//==========================================================================
	private var defaultContainer:DisplayObjectContainer;
	private var modules:Array = [];
	//mask字典
	private var maskRecord:Dictionary = new Dictionary();
	
	private var maskColor:uint = 0x333333;
	private var maskAlpha:Number = 0.4;
	
	private var orderPopups:Array = [];
	
	/**
	 * 模式窗口数量
	 */    
	private var modalNum:int = 0;
	
	//==========================================================================
	//  Methods
	//==========================================================================
	/**
	 * 设置默认的容器
	 * @param container
	 *
	 */
	public function setDefaultContainer(container:DisplayObjectContainer):void
	{
		defaultContainer = container;
		if(defaultContainer.stage)
		{
			defaultContainer.stage.addEventListener(Event.RESIZE,
				autoResizeHandler);
		}
		
	}
	/**
	 * Pops up a top-level window.
	 * It is good practice to call <code>removePopUp()</code> to remove popups
	 * created by using the <code>addPopUp()</code> method.
	 *
	 * <p><b>Example</b></p>
	 *
	 * <pre>var tw = new TitleWindow();
	 *    tw.title = "My Title";
	 *    mx.managers.PopUpManager.addPopUp(tw, pnl, false);</pre>
	 *
	 * <p>Creates a popup window using the <code>tw</code> instance of the
	 * TitleWindow class and <code>pnl</code> as the Sprite for determining
	 * where to place the popup.
	 * It is defined to be a non-modal window.</p>
	 *
	 * @param window The DisplayObject to be popped up.
	 *
	 * @param container 窗口添加的位置，如果为空，则添加到默认的容器，如果没有设置
	 * 默认的位置，则不会被添加到舞台中。
	 *
	 * @param autoResize 是否自动设置大小
	 *
	 * @param autoToFornt 是否当鼠标点击时处于最前面
	 */
	public function addPopUp(popUp:DisplayObject,
							 container:DisplayObjectContainer = null,
							 autoResize:Boolean = false,
							 autoToFornt:Boolean = false,
							 modal:Boolean = false, 
							 tweenFlag:Boolean = true):void
	{
		if (popUp)
		{
			//            popUp.filters = [new GlowFilter(0, 0.5, 12, 12)];
			var tempContainer:DisplayObjectContainer = (container != null) ? container : defaultContainer;
			if (tempContainer)
			{
				if (modal)
				{
					addMask(tempContainer, popUp);
				}
				tweenFlag ? TweenUtil.popUp(tempContainer, popUp) : 
					tempContainer.addChild(popUp);
			}
			
			if(autoResize)
			{
				modules.push(popUp);
				resize(popUp);
			}
			if(autoToFornt)
			{
				popUp.addEventListener(MouseEvent.MOUSE_DOWN,
					popUp_mouseDownHandler);
				bringToFront(popUp);
			}
		}
	}
	
	/**
	 * 检验是否可以弹出新的模式窗口
	 */    
	private function checkOrderPopUp():void
	{
		if (orderPopups.length && modalNum == 0)
		{
			var params:Array = orderPopups.shift() as Array;
			var display:DisplayObject = params[0];
			addPopUp.apply(null, params);
			centerPopUp(display);
		}
	}
	
	/**
	 * 按顺序弹出模式窗口
	 * @param popUp
	 */    
	public function addOrderPopUp(popUp:DisplayObject):void
	{
		orderPopups.push([popUp, null, false, false, true, true]);
		checkOrderPopUp();
	}
	
	/**
	 * 设置模式窗口的遮罩
	 * @param color
	 * @param alpha
	 * 
	 */    
	public function setModalMask(color:uint, alpha:Number):void
	{
		maskColor = color;
		maskAlpha = alpha;
	}
	
	public function resize(popUp:DisplayObject):void
	{
		if (popUp && popUp.parent && popUp.stage)
		{
			centerPopUp(popUp);
		}
	}
	
	/**
	 * Removes a popup window popped up by
	 * the <code>createPopUp()</code> or <code>addPopUp()</code> method.
	 *
	 * @param window The DisplayObject representing the popup window.
	 */
	public function removePopUp(popUp:DisplayObject):void
	{
		if (popUp && popUp.parent)
		{
			//删除遮罩
			if (maskRecord[popUp])
			{
				popUp.parent.removeChild(maskRecord[popUp]);
				delete maskRecord[popUp];
				modalNum--;
				checkOrderPopUp();
			}
			TweenUtil.remove(popUp.parent, popUp);
			//            popUp.parent.removeChild(popUp);
			ArrayUtil.removeValueFromArray(modules, popUp);
			popUp.removeEventListener(MouseEvent.MOUSE_DOWN,
				popUp_mouseDownHandler);
		}
	}
	
	/**
	 * Centers a popup window over whatever window was used in the call
	 * to the <code>createPopUp()</code> or <code>addPopUp()</code> method.
	 *
	 * @param popUp The DisplayObject representing the popup.
	 */
	public function centerPopUp(popUp:DisplayObject):void
	{
		if (popUp && popUp.parent)
		{
			if (popUp.parent is Stage)
			{
				popUp.x = int((popUp.stage.stageWidth - popUp.width) / 2);
				popUp.y = int((popUp.stage.stageHeight - popUp.height) / 2);
			}
			else
			{
				popUp.x = int((popUp.parent.width - popUp.width) / 2);
				popUp.y = int((popUp.parent.height - popUp.height) / 2);
			}
		}
	}
	
	/**
	 * Makes sure a popup window is higher than other objects in its child list
	 * The SystemManager does this automatically if the popup is a top level window
	 * and is moused on,
	 * but otherwise you have to take care of this yourself.
	 *
	 * @param The DisplayObject representing the popup.
	 */
	public function bringToFront(popUp:DisplayObject):void
	{
		if (popUp)
		{
			DepthUtil.bringToTop(popUp);
		}
	}
	
	/**
	 * 添加遮罩
	 *
	 */
	private function addMask(parentContainer:DisplayObjectContainer,
							 popUp:DisplayObject):void
	{
		var mask:Sprite = new Sprite();
		var width:Number = (parentContainer == parentContainer.stage)?
			parentContainer.stage.stageWidth:parentContainer.width;
		var height:Number = (parentContainer == parentContainer.stage)?
			parentContainer.stage.stageHeight:parentContainer.height;
		mask.graphics.clear();
		mask.graphics.beginFill(maskColor, maskAlpha);
		mask.graphics.drawRect(parentContainer.x, parentContainer.y,
			width, height);
		mask.graphics.endFill();
		parentContainer.addChild(mask);
		maskRecord[popUp] = mask;
		modalNum++;
	}
	//==========================================================================
	//  Event Handlers
	//==========================================================================
	private function autoResizeHandler(event:Event):void
	{
		for each(var display:DisplayObject in modules)
		{
			resize(display);
		}
		
		//遮罩resize
		for (var popUp:Object in maskRecord)
		{
			if (popUp && popUp.parent && popUp.stage && maskRecord[popUp])
			{
				var parentObj:DisplayObject = (popUp.parent != popUp.stage) ?
					popUp.parent : popUp.stage;
				maskRecord[popUp].width = parentObj.width;
				maskRecord[popUp].height = parentObj.height;
				centerPopUp(popUp as DisplayObject);
			}
		}
	}
	
	private function popUp_mouseDownHandler(event:MouseEvent):void
	{
		bringToFront(DisplayObject(event.currentTarget));
	}
}
}